サービスメッシュについて理解する
カナダ・バンクーバーオフィスの山口です。
Kubernetes でマイクロサービスのアプリケーション開発をしていると、一度はサービスメッシュという言葉を聞いたことがあるのではないでしょうか。
マイクロサービス間の通信制御において、サービスメッシュは非常に強力な武器となります。しかし、Kubernetes クラスターへサービスメッシュを導入するのは多少敷居が高く、躊躇している方も多いかと思います。
今回はサービスメッシュの概要についてご説明します。そして次回以降で、EKS クラスター上で Istio や App Mesh といった主要なサービスメッシュの導入方法についてお伝えしていきます。
サービスメッシュとは
サービスメッシュは、アプリケーションレベルの通信をアプリケーション自身が制御するのではなく、インフラストラクチャ側で制御できるようにする技術です。
例えば、以下のアーキテクチャを考えてみましょう。あるプロジェクトではマイクロサービスアーキテクチャを採用しており、各チームが独立してアプリケーションの開発をしています。チーム A では Node.js を使い、チーム B は Java を、チーム C は Go を、チーム D は Ruby を使って開発をしています。
また、それぞれのチームでは VM を使ったりコンテナで実装したりと、チーム毎に異なるコンピューティングプラットフォームを使用しています。
このとき、それぞれのアプリケーションが実装する通信制御として、以下のようなものがあるかと思います。
- HTTP 通信のリトライやタイムアウト
- 通信のトレーシングやログ、メトリクスの取得
- TLS を使用した暗号化通信
各チームは、これらの機能をアプリケーションに組み込む必要があります。それも、リトライ処理やログのフォーマット等について機能を統一させる必要があり、開発者からすると負担が大きい作業となります。
リソースに余裕がある場合は、共通基盤チームのようなものを作り、通信の仕組みである共通ライブラリを各アプリケーション毎に実装し配布することで対応することも可能です。
しかし、共通ライブラリの実装には以下のような課題があります。
- 各チームで使っている言語の数が増えれば増えるほどそれぞれの言語に対応したライブラリも増加し、共通基盤チームの負担が増加する
- そもそも使用している言語のライブラリがない
- 共通ライブラリを導入することでアプリケーションの依存関係と衝突する可能性があり、その場合アプリケーション開発者は共通ライブラリを考慮した上でアプリケーションコードを修正する必要が出てくる
- VM だと動かない、コンテナだと動かない、XX 環境だと動かない、といった状況が発生する
このように、共通ライブラリの導入はアプリケーション開発者と共通基盤チーム共に運用負荷を増大させます。
そこで出てきた解決法が、アプリケーションから通信処理を分離する方法です。マイクロサービス間の通信処理はアプリケーション側では実装せずに、インフラストラクチャ側で一括管理をしてしまおう、といった考え方です。これを実現する技術を、サービスメッシュといいます。そうすれば各チームはアプリケーションの開発だけに注力することができ、通信処理の部分に関してはインフラストラクチャ側に任せれば済むようになります。
仕組み
アプリケーションから通信処理を分離すると書きましたが、ではその仕組みはどのようになっているのでしょうか?
Kubernetes を使った実装では、アプリケーションコンテナは論理上 pod の中に存在しています。アプリケーションから通信処理に関する部分だけを分離するには、この pod の中に別のコンテナを組み込みます。これはプロキシコンテナと言われるもので、マイクロサービス間の通信を制御するのに特化したプロキシとなります。このようにすることで、これまではアプリケーション側で実装が必要だった通信処理の役割を、代わりにプロキシが担うようになります。
プロキシコンテナは、特定の pod だけではなく Kubernetes クラスターに存在する全ての pod に挿入されます。そうすると、各 pod が他の pod と通信を行う際はプロキシを通じて行うことになり、その様子が網の目 (メッシュ) のように張り巡らされます。これがサービスメッシュと言われる所以です。また、プロキシコンテナは全てのアプリケーションコンテナに付随してデプロイされるため、サイドカーコンテナとも呼ばれます。
有名なプロキシに、envoy というオープンソースのソフトウェアがあります。
envoy は C++ で実装されている、L4/L7 に対応したオープンソースのプロキシソフトウェアです。サービス間のネットワーク制御をライブラリではなく、ネットワークプロキシとして提供することを目的としています。envoy はプロキシとして広く使われており、envoy を使用した代表的なサービスメッシュサービスに Istio サービスメッシュや AWS の独自機能である App Mesh があります。
ここで、pod A が pod B と通信を行う場合を考えてみましょう。下の図では、pod 間におけるトラフィックの状態を表しています。
pod A から pod B に向かうトラフィックは、pod A から直接 pod B のアプリケーションコンテナと接続するのではなく、まず同じ pod A 内にあるプロキシを経由します。同様に、pod B 側に入ってきたトラフィックは pod B 内にあるプロキシを経由してからアプリケーションコンテナに接続します。
このように、サービスメッシュでは全ての pod 内にプロキシを実装しており、そのため pod 間で発生する通信は必ずプロキシを経由することになります。通信制御をプロキシに任せることで、アプリケーション側での開発負担が大幅に削減されます。
コントロールプレーン と データプレーン
サービスメッシュのアーキテクチャは、大きくコントロールプレーンとデータプレーンに分かれています。
これまでマイクロサービス間の通信方法についてみてきましたが、これらは全てデータプレーンとしての機能となります。データプレーンでは、クラスター内の全ての pod にプロキシをデプロイしてマイクロサービス間の通信を制御します。
これらのプロキシを管理するのが、コントロールプレーンとなります。コントロールプレーンでは、プロキシの設定やトラフィックのルーティングを行います。データプレーンであるプロキシをコントロールする司令塔の役割を担っています。
上の図は Istio サービスメッシュの各コンポーネントを表したものです。Istio サービスメッシュでは、コントロールプレーンのコンポーネントである istiod がデータプレーンの envoy プロキシを管理しています。
まとめ
サービスメッシュを活用すると、従来のようにアプリケーション同士が直接通信を行うのではなく、プロキシを経由して通信をすることで必要な機能をプロキシ側で実装することが可能となります。アプリケーションレベルの通信制御をサービスメッシュの基盤で行うのでアプリケーションに組み込む必要がなくなり、アプリケーション開発者の負担を大幅に削減することができます。
また、サービスメッシュのアーキテクチャは、マイクロサービス間の通信制御を行うデータプレーンとそれを管理するコントロールプレーンに分けられ、それぞれが独立して機能しています。
今回はサービスメッシュのメリットやその仕組みについて簡単にご説明しました。次回以降は、サービスメッシュの代表格である Istio サービスメッシュや App Mesh を EKS クラスター上で実装する方法についてお伝えしていきます。